package com.notify.paynotify.controller;

import com.alibaba.fastjson2.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.*;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping(value = "/notify")
public class NotifyController {

    private Logger logger = LoggerFactory.getLogger(NotifyController.class);

    @RequestMapping(value = "/callback")
    public String callback(HttpServletRequest request, HttpServletResponse response) {
        try {
            String method = request.getMethod();
            logger.info("请求方式：{}", method);
            logger.info("请求地址：{}", request.getRemoteAddr());
            String read = read(request);
            if (null == read && "".equals(read)) {
                logger.error("支付回调通知，接收到的数据为null或空串");
                throw new Exception("支付回调通知，接收到的数据为null或空串");
            }
            Map<String, String> map = xmlToMap(read);
            logger.info("微信回调JSON {}\n", JSONObject.toJSONString(map));
            // 注意特殊情况：订单已经退款，但收到了支付结果成功的通知，不应把商户侧订单状态从退款改成支付成功
            //通信标识，非交易标识，交易是否成功需要查看result_code来判断
            String returnCode = map.get("return_code").trim();
            if (null == returnCode || "FAIL".equals(returnCode)) {
                String returnMsg = map.get("return_msg").trim();
                logger.error("支付回调通知，{}", returnMsg);
                throw new Exception("支付回调通知，" + returnMsg);
            }
            String resultCode = map.get("result_code").trim();//业务结果
            if (null == resultCode || "FAIL".equals(resultCode)) {
                String returnMsg = map.get("err_code_des").trim();//返回信息
                logger.error("支付回调通知，{}", returnMsg);
                throw new Exception("支付回调通知，" + returnMsg);
            }
            //系统支付订单编号
            String outTradeNo = map.get("out_trade_no").trim();//订单号
            //交易类型，JSAPI
            String tradeType = map.get("trade_type").trim();
            //付款银行
            String bankType = map.get("bank_type").trim();
            //微信支付订单号
            String transactionId = map.get("transaction_id").trim();
            //支付金额
            String cashFee = map.get("cash_fee").trim();
            BigDecimal payAmount = new BigDecimal(cashFee).divide(BigDecimal.valueOf(100));
            //订单金额
            String totalFee = map.get("total_fee").trim();
            //支付时间
            String timeEnd = map.get("time_end").trim();
            //是否关注公众账号
            String subscribe = map.get("is_subscribe").trim();
            //原路返回的数据包
            String attach = map.get("attach").trim();
            logger.info("支付回调成功");
            return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
        } catch (Exception e) {
            logger.error("支付回调失败");
            logger.error("{}", e);
            return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[回调失败]]></return_msg></xml>";
        }
    }


    public String read(HttpServletRequest request) {
        InputStream is = null;
        BufferedReader reader = null;
        try {
            is = request.getInputStream();
            //将InputStream转换成String
            reader = new BufferedReader(new InputStreamReader(is));
            StringBuilder sb = new StringBuilder();
            String line = null;
            while ((line = reader.readLine()) != null) {
                sb.append(line + "\n");
            }
            String resXml = sb.toString();
            logger.info("微信支付源数据：\n{}", resXml);
            return resXml.trim();
        } catch (Exception e) {
            logger.error("{}", e);
        } finally {
            try {
                is.close();
                reader.close();
            } catch (IOException e) {

            }
        }
        return null;
    }

    public static Map<String, String> xmlToMap(String strXML) throws Exception {
        Map<String, String> data = new HashMap();
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
        InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
        Document doc = documentBuilder.parse(stream);
        doc.getDocumentElement().normalize();
        NodeList nodeList = doc.getDocumentElement().getChildNodes();

        for (int idx = 0; idx < nodeList.getLength(); ++idx) {
            Node node = nodeList.item(idx);
            if (node.getNodeType() == 1) {
                Element element = (Element) node;
                data.put(element.getNodeName(), element.getTextContent());
            }
        }
        try {
            stream.close();
        } catch (Exception var10) {
        }
        return data;
    }

}
